package com.xc.quickstart.infrastructure.redis;

import com.xc.quickstart.common.properties.RedissonProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.JedisPoolConfig;

import java.util.Objects;


@Configuration
@EnableConfigurationProperties(RedissonProperties.class)
public class RedisTemplateConfig {

    @Autowired
    private RedissonProperties redissonProperties;

    @Bean("StringRedisTemplate")
    public StringRedisTemplate stringRedisTemplate() {
        if (Objects.isNull(redissonProperties)) {
            throw new IllegalArgumentException("redis config empty.");
        }

        JedisConnectionFactory factory = jedisConnectionFactory(
                redissonProperties.getHost(), redissonProperties.getPort(), redissonProperties.getDatabase(), redissonProperties.getPassword(),
                1024, 1024, 1000, 300000, 16,
                3000, false, true);
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(factory);

        return template;
    }

    private JedisPoolConfig jedisPoolConfig(Integer maxIdle,
                                            Integer maxTotal,
                                            Integer maxWaitMillis,
                                            Integer minEvictableIdleTimeMillis,
                                            Integer numTestsPerEvictionRun,
                                            long timeBetweenEvictionRunsMillis,
                                            boolean testOnBorrow,
                                            boolean testWhileIdle) {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        // 最大空闲数
        jedisPoolConfig.setMaxIdle(maxIdle);
        // 连接池的最大数据库连接数
        jedisPoolConfig.setMaxTotal(maxTotal);
        // 最大建立连接等待时间
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        // 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
        jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        // 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
        jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        // 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        // 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
        jedisPoolConfig.setTestOnBorrow(testOnBorrow);
        // 在空闲时检查有效性, 默认false
        jedisPoolConfig.setTestWhileIdle(testWhileIdle);
        return jedisPoolConfig;
    }


    private JedisConnectionFactory jedisConnectionFactory(String host,
                                                          int port,
                                                          int db,
                                                          String password,
                                                          Integer maxIdle,
                                                          Integer maxTotal,
                                                          Integer maxWaitMillis,
                                                          Integer minEvictableIdleTimeMillis,
                                                          Integer numTestsPerEvictionRun,
                                                          long timeBetweenEvictionRunsMillis,
                                                          boolean testOnBorrow,
                                                          boolean testWhileIdle) {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        redisStandaloneConfiguration.setDatabase(db);
        redisStandaloneConfiguration.setPassword(RedisPassword.of(password));

        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpb =
                (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration.builder();
        jpb.poolConfig(jedisPoolConfig(maxIdle, maxTotal, maxWaitMillis, minEvictableIdleTimeMillis, numTestsPerEvictionRun, timeBetweenEvictionRunsMillis, testOnBorrow, testWhileIdle));


        return new JedisConnectionFactory(redisStandaloneConfiguration, jpb.build());
    }
}
